#!/usr/bin/env python

#
# fusionfs.py
#
# Copyright 2007 Helsinki Institute for Information Technology
# and the authors.
#
# Authors: Toni Ruottu <toni.ruottu@iki.fi>
#

# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

from fusion.db.db import DB
from fuse import Fuse
import re
import sys

class Fusion(Fuse):
    
    dbfile = '~/.fusion/fusion.db'

    def __init__(self, *args, **kw):

        Fuse.__init__(self, *args, **kw)
    
    def __parsepath(self, path):

        c = ''
        p = ''

        # match collection id and subpath
        match = re.search('^/[^/]*([0-9a-f]{40})(.*)$', path)

        if match:
            c = match.group(1)
            p = match.group(2)

        return (c,p)

    def getattr(self, path):

        # Dictionary from "ls -l" notation to "stat --format=%f" values
        permissions = {
            "lrwxrwxrwx":0xa1ff,
            "dr-xr-xr-x":0x416d,
            "-r--r--r--":0x8124
        }

        # default attributes
        attributes = [
            permissions["dr-xr-xr-x"], # 0 permissions
            0L, # 1 inode
            0L, # 2 device
            1,  # 3 number of hard links
            0,  # 4 user
            0,  # 5 group
            0L, # 6 size
            0,  # 7 time of last access
            0,  # 8 modification time
            0   # 9 os specific time
        ]
        
        # title link
        if re.search('^/[^/]* \([0-9a-f]*\)$', path):
            attributes[0] = permissions["lrwxrwxrwx"]

        (c,p) = self.__parsepath(path)

        if p:
            db = DB(self.dbfile)
            value = db.get(c,p)
            db.close()

            if value is not None:
                attributes[0] = permissions["-r--r--r--"]
                attributes[6] = len(value)

        return tuple(attributes)

    def readlink(self, path):

        #Extract collection name from symbolic link filename
        match = re.search('^/[^/]* \(([0-9a-f]{40})\)$', path)

        if match:
            return match.group(1)
            
        return None

    def getdir(self, path):

        db = DB(self.dbfile)

        dirs = set(['.','..'])

        if path == '/':

            for c in db.list_collections():

                dirs.add(c)

                title = db.get_text(c, 'info/title')

                if title:
                    dirs.add(title.encode('utf-8')+" ("+c+")")
        else:
        
           (c,p) = self.__parsepath(path)
            
           for path in db.keys(c, p):
               if path:
                   if '/' in path:
                       path = path[:path.index('/')]
                   dirs.add(str(path))
        db.close()

        #BUG: What are the zeros for?
        return [(dir,0) for dir in dirs]


    def open(self, path, flags):

        pass
    
    def read(self, path, length, offset):

        value = None

        (c,p) = self.__parsepath(path)

        db = DB(self.dbfile)

        if p:
            value = db.get(c,p)

        db.close()

        if value:
            value = value[offset:offset+length]

        return value

    def release(self, path, flags):

        pass

if __name__ == '__main__':

    argv = sys.argv
    argc = len(argv)

    if argc < 2:
        # BUG: It is also possible to pass some generic mount options,
        # but I have no idea how they work.
        print "Usage: "+argv[0]+" mountpoint"

    else:
        server = Fusion()

        # BUG: Commented multithraeding out because it results in warning
        # fuse: warning: buffer size too small: 4
        #server.multithreaded = 1;

        server.main()
